package project.base;

import java.nio.charset.Charset;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import online.model.UniModel;
import online.model.UniModelImpl;
import common.db.JdbcSource;
import common.sql.QueryUtil;
import core.util.bean.CamelCase;

/**
 * クエリ親クラス
 *
 * @author Tadashi Nakayama
 * @version 1.0.0
 */
public abstract class QueryAbstract extends ServiceAbstract {

	/** CamelCase */
	private final CamelCase cc = new CamelCase(true);
	/** エンコード */
	private Charset charset = JdbcSource.getCharset();
	/** スキーマ */
	private String schema;
	/** 画面ID */
	private String gid;

	/**
	 * エンコード設定
	 *
	 * @param val エンコード
	 */
	public final void setCharset(final String val) {
		if (!Objects.toString(val, "").isEmpty()) {
			this.charset = Charset.forName(val);
		}
	}

	/**
	 * エンコード取得
	 *
	 * @return エンコード
	 */
	public final Charset getCharset() {
		return this.charset;
	}

	/**
	 * 接続名設定
	 * @param val 接続名
	 */
	public final void setSchema(final String val) {
		this.schema = val;
		this.charset = JdbcSource.getCharset(val);
	}

	/**
	 * 接続名取得
	 * @return 接続名
	 */
	protected final String getSchema() {
		return this.schema;
	}

	/**
	 * 画面ID設定
	 * @param val 画面ID
	 */
	public final void setGid(final String val) {
		this.gid = val;
	}

	/**
	 * ファイルからSQL取得
	 * @return SQL
	 */
	protected final String getSqlFromFile() {
		return QueryUtil.getSqlFromFile(this.getClass().getName());
	}

	/**
	 * 汎用モデル初期化
	 *
	 * @param rs 結果セット
	 * @return 汎用モデル
	 * @throws SQLException SQL例外
	 */
	protected final UniModel initModel(final ResultSet rs) throws SQLException {
		UniModel ret = new UniModelImpl();

		ResultSetMetaData rsmd = rs.getMetaData();
		for (int i = 1; i <= rsmd.getColumnCount(); i++) {
			ret.noValue(toCamelCase(rsmd.getColumnLabel(i)));
		}

		return ret;
	}

	/**
	 * 値追加
	 * @param um 汎用モデル
	 * @param rs 結果セット
	 * @param i カラム位置
	 * @throws SQLException SQL例外
	 */
	protected final void addValue(final UniModel um,
			final ResultSet rs, final int i) throws SQLException {

		ResultSetMetaData rsmd = rs.getMetaData();
		String key = toCamelCase(rsmd.getColumnLabel(i));
		switch (rsmd.getColumnType(i)) {
			case java.sql.Types.DATE:
				um.addValue(key, rs.getDate(i));
				return;
			case java.sql.Types.TIME:
				um.addValue(key, rs.getTime(i));
				return;
			case java.sql.Types.TIMESTAMP:
				um.addValue(key, rs.getTimestamp(i));
				return;
			case java.sql.Types.CHAR:
			case java.sql.Types.VARCHAR:
				um.addValue(key, rs.getString(i));
				return;
			case java.sql.Types.NUMERIC:
			case java.sql.Types.DECIMAL:
				um.addValue(key, rs.getBigDecimal(i));
				return;
			default:
				break;
		}

		switch (rsmd.getColumnType(i)) {
			case java.sql.Types.SMALLINT:
			case java.sql.Types.INTEGER:
				if (rs.getObject(i) == null) {
					um.addValue(key, Integer.class.cast(null));
				} else {
					um.addValue(key, Integer.valueOf(rs.getInt(i)));
				}
				break;
			case java.sql.Types.BIGINT:
				if (rs.getObject(i) == null) {
					um.addValue(key, Long.class.cast(null));
				} else {
					um.addValue(key, Long.valueOf(rs.getLong(i)));
				}
				break;
			case java.sql.Types.DOUBLE:
			case java.sql.Types.FLOAT:
				if (rs.getObject(i) == null) {
					um.addValue(key, Double.class.cast(null));
				} else {
					um.addValue(key, Double.valueOf(rs.getDouble(i)));
				}
				break;
			default:
				break;
		}
	}

	/**
	 * CamelCase化
	 * @param val 文字列
	 * @return CamelCase文字列
	 */
	protected final String toCamelCase(final String val) {
		return this.cc.toCamelCase(val);
	}

	/**
	 * 共通パラメタ設定
	 * @param um パラメタマップ
	 * @return map 設定マップ
	 */
	protected final Map<String, Object> toParamMap(final UniModel um) {
		Map<String, Object> map = new HashMap<>();
		if (um != null) {
			map.putAll(um.toMap());
		}
		putCommonParameter(map);
		return map;
	}

	/**
	 * 共通パラメタ設定
	 * @param map 設定マップ
	 */
	protected final void putCommonParameter(final Map<String, Object> map) {
		map.putAll(super.getSessionUser().getAttributeMap());
		map.putAll(super.getProperty());
		map.put("Uid", super.getUid());
		map.put("DateTime", super.getDateTime());
		// TODO 権限設定（開示区分）
		map.put("Kaiji", this.gid);
	}
}
